package org.axeidls.util.jeval;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sourceforge.jeval.Evaluator;

/**
 * 表达式计算工具
 * 支持#{variable} 取值表达式
 * @author CaiDongyu
 */
public final class JevalUtil {

	private JevalUtil() {}
	
	public static String calcu(String expr,Map<String,String> params,int maxDotlen)throws Exception {
		Evaluator evaluator = new Evaluator();
		for(String key:params.keySet()) {
			evaluator.putVariable(key, params.get(key));
		}
		String result = evaluator.evaluate(expr);
		result = new BigDecimal(result).setScale(maxDotlen,RoundingMode.HALF_UP).toPlainString();
		while(result.endsWith("0")) {
			result = result.substring(0,result.length()-1);
		}
		if(result.endsWith(".")) {
			result = result.substring(0,result.length()-1);
		}
		return result;
	}

	private static Variable[] listVariables(String expr) {
		//对取值变量做jeval处理，需要加上#{}
		Pattern pattern = Pattern.compile("#\\{([^\\{]*)\\}");
		Matcher matcher = pattern.matcher(expr);
		Set<String> variableSet = new HashSet<>();
		while(matcher.find()) {
			String variable = matcher.group(1).trim();
			variableSet.add(variable);
		}
		
		Variable[] variables = new Variable[variableSet.size()];
		int i=0;
		for(String variable:variableSet) {
			variables[i] = new Variable();
			variables[i].setRawName(variable);
			variables[i].setFlag("?"+i);
			i++;
		}
		return variables;
	}
	
	public static Expression castExpression(String expr) {
		Variable[] variables = listVariables(expr);
		for(Variable variable:variables) {
			expr = expr.replace("#{"+variable.getRawName()+"}", "#{"+variable.getFlag()+"}");
		}
		expr = castJevalMaxMin(expr, "max");
		expr = castJevalMaxMin(expr, "min");
		Expression expression = new Expression();
		expression.setExpression(expr);
		expression.setVariables(variables);
		return expression;
	}
	

	private static String castJevalMaxMin(String expr,String func) {
		expr = expr.replaceAll("、", ",");
		StringBuilder buf = new StringBuilder();
		Pattern pattern = Pattern.compile(func+"\\(.+\\)");
		Matcher matcher = pattern.matcher(expr);
		while(matcher.find()) {
			String group = matcher.group();
			String header = expr.substring(0,expr.indexOf(group));
			buf.append(header);
			String str = group.replace(func+"(", "").replace(")", "").replaceAll(" ", "");
			String[] split = str.split(",");
			if(split.length <= 2) {
				buf.append(func).append("(").append(split[0]).append(",").append(split[1]).append(")");
			}else {
				buf.append(func).append("(").append(split[0]).append(",");
				for(int i=1;i<split.length-1;i++) {
					buf.append(func).append("(").append(split[i]).append(",");
				}
				buf.append(split[split.length-1]);
				for(int i=0;i<split.length-1;i++) {
					buf.append(")");
				}
			}
			expr = expr.substring(expr.indexOf(group)+group.length());
			matcher = pattern.matcher(expr);
		}
		buf.append(expr);
		expr = buf.toString();
		return expr;
	}
	
	public static void main(String[] args) {
		Map<String,String> params = new HashMap<>();
		params.put("电压", "5");
		params.put("电流", "2");
		try {
			String calcu = calcu("#{电压}/#{电流}", params,10);
			System.out.println(calcu);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
